<?php

namespace App\Storage;

use EasySwoole\EasySwoole\ServerManager;
use EasySwoole\Component\Singleton;
use EasySwoole\Component\TableManager;
use Swoole\Table;

/**
 *  在线终端
 *
 * @Author LYC 17750800820@163.com
 * @DateTime 2020-04-22 14:33:07
 *
 */
class OnlineClient
{
    use Singleton;
    protected $table;  // 储存终端信息的Table

    // const INDEX_TYPE_FD_ID = 1;

    /**
     * OnlineClient constructor.
     */
    public function __construct()
    {
        TableManager::getInstance()->add('onlineClients', [
            'device_serial_no'=>['type'=>Table::TYPE_STRING, 'size'=>128],
            'last_heartbeat' => ['type' => Table::TYPE_INT, 'size' => 16]
        ]);

        $this->table = TableManager::getInstance()->get('onlineClients');
    }

    /**
     * 设置一个终端
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-22 14:51:30
     * @param integer $fd
     * @param string $device_serial_no
     * @return void
     */
    public function set($fd, $device_serial_no)
    {
        return $this->table->set($fd, [
            'device_serial_no' => $device_serial_no,
            'last_heartbeat' => time()
        ]);
    }

    /**
     * 获取所有终端设备
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-27 13:08:26
     * @param string $device_serial_no
     * @return array $clients
     */
    // public function getClient($device_serial_no)
    // {
    //     $client = null;
    //     // 千万不要用数组方式读取Table , 可以foreach出来 https://www.easyswoole.com/Cn/Swoole/ProcessCommunication/table.html
    //     foreach ($this->table as $key => $item) {
    //         if ($device_serial_no == $item['device_serial_no']) {
    //             $client = $key;
    //             break;
    //         }
    //     }
    //     return $client;
    // }

    /**
     * 获取所有终端设备
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-27 13:08:26
     * @return array $clients
     */
    public function getClients()
    {
        $clients = [];
        // 千万不要用数组方式读取Table , 可以foreach出来 https://www.easyswoole.com/Cn/Swoole/ProcessCommunication/table.html
        foreach ($this->table as $item) {
            $clients []= $item['device_serial_no'];
        }
        return $clients;
    }
    /**
     * 获取一个终端
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-22 15:01:38
     * @param integer $fd
     * @return void
     */
    public function get($fd)
    {
        $info = $this->table->get($fd);
        return is_array($info) ? $info : null;
    }

    /**
     * 获得指定在线设备对应的fd
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-23 00:02:36
     * @param string $device_serial_no
     * @return void
     */
    public function getClient($device_serial_no)
    {
        $table = $this->table;
        $fd = null;
        foreach ($table as $key => $val) {
            if ($val['device_serial_no'] == $device_serial_no) {
                $fd = $key;
                break;
            }
        }
        return $fd;
    }
    /**
     * 更新一条终端信息
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-22 15:02:27
     * @param integer $fd
     * @param string $data
     * @return void
     */
    public function update($fd, $data)
    {
        $info = $this->get($fd);
        if (!empty($info)) {
            foreach ($data as $key => $val) {
                $info[$key] = $val;
            }
            $this->table->set($fd, $info);
        }
    }

    /**
     * 删除一个终端
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-22 15:11:39
     * @param integer $fd
     * @return void
     */
    public function delete($fd)
    {
        if ($this->table->exist($fd)) {
            $this->table->del($fd);
        }
    }

    /**
     * 心跳检查
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-22 15:13:05
     * @param integer $ttl
     * @return void
     */
    public function heartbeatCheck($ttl = 60)
    {
        // 千万不要用数组方式读取Table , 可以foreach出来 https://www.easyswoole.com/Cn/Swoole/ProcessCommunication/table.html
        foreach ($this->table as $fd => $item) {
            $time = $item['last_heartbeat'];
            // 上次心跳时间+心跳周期时间 < 当前时间, 判断为掉线, 删除这条终端信息
            if (($time + $ttl) < time()) {
                $this->delete($fd);
                // 关闭该连接
                $server = ServerManager::getInstance()->getSwooleServer();
                $server->close($fd);
            }
        }
    }

    /**
     *  更新上次心跳时间
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-22 15:18:31
     * @param integer $fd
     * @return void
     */
    public function updateHeartbeat($fd)
    {
        $this->update($fd, [
            'last_heartbeat' => time()
        ]);
    }

    /**
     * 直接获取当前的表
     * @return Table|null
     */
    public function table()
    {
        return $this->table;
    }
}
